///|
pub struct UnlimitInt {
  priv sign : Sign?
  priv value : String
}

///|
pub fn UnlimitInt::default() -> UnlimitInt {
  return UnlimitInt::make_zero()
}

///|
pub fn UnlimitInt::make_zero() -> UnlimitInt {
  { sign: None, value: "0" }
}

///|
fn UnlimitInt::is_int(str : String) -> Bool {
  // check null string
  guard str.length() > 0 && str.is_empty() == false else { return false }
  // let digitals = "0123456789"
  // let mut is_digital = true
  // let mut positive_count = 0
  // let mut negative_count = 0
  // for index = 0; index < str.length(); index = index + 1 {
  //   if '+' == str[index] {
  //     positive_count += 1
  //     continue
  //   }
  //   if '-' == str[index] {
  //     negative_count += 1
  //     continue
  //   }
  //   if false == digitals.contains_char(str[index]) {
  //     is_digital = false
  //     break
  //   }
  // }
  // if positive_count > 1 || negative_count > 1 {
  //   is_digital = false
  // }
  // if positive_count == 1 && '+' != str[0] {
  //   is_digital = false
  // }
  // if negative_count == 1 && '-' != str[0] {
  //   is_digital = false
  // }
  // return is_digital
  let symbols = "+="
  let real_str = if symbols.contains_char(str.char_at(0)) {
    str.substring(start=1)
  } else {
    str
  }
  return UnlimitInt::is_pure_digital(real_str)
}

///|
fn UnlimitInt::is_pure_digital(str : String) -> Bool {
  guard str.length() > 0 && str.is_empty() == false else { return false }
  let digitals = "0123456789"
  for index = 0; index < str.length(); index = index + 1 {
    guard digitals.contains_char(str.char_at(index)) else { return false }

  }
  return true
}

///|
pub type! NotIntStringError String

///|
pub type! NotPureDigitalStringError String

///|
fn UnlimitInt::check_str(int_str : String) -> NotIntStringError? {
  let error = NotIntStringError("value is not int string")
  guard UnlimitInt::is_int(int_str) else { return Some(error) }
  return None
}

///|
fn UnlimitInt::check_pure_digital_str(
  digital_str : String
) -> NotPureDigitalStringError? {
  let error = NotPureDigitalStringError("value is not pure digital string")
  guard UnlimitInt::is_pure_digital(digital_str) else { return Some(error) }
  return None
}

///|
pub fn UnlimitInt::new(int_str : String) -> UnlimitInt!NotIntStringError {
  let check = UnlimitInt::check_str(int_str)
  guard check is None else { raise check.unwrap() }

  // ensure zero value
  let mut zero_count = 0
  for index = 0; index < int_str.length(); index = index + 1 {
    if '0' == int_str.char_at(index) {
      zero_count += 1
    }
  }
  // all is zero
  if zero_count == int_str.length() {
    let ui = { sign: None, value: "0" }
    return ui
  }
  // first char is polarity, other all is zero
  let first_chat = int_str.char_at(0)
  if "+-".contains_char(first_chat) && zero_count == int_str.length() - 1 {
    let ui = { sign: None, value: "0" }
    return ui
  }
  match first_chat {
    '+' => { sign: Some(Positive), value: int_str.substring(start=1) }
    '-' => { sign: Some(Negative), value: int_str.substring(start=1) }
    _ => { sign: Some(Positive), value: int_str }
  }
}

///|
// pub fn UnlimitInt::make_new(
//   polarity : Polarity,
//   digital_str : String
// ) -> UnlimitInt!NotPureDigitalStringError {
//   let check = UnlimitInt::check_pure_digital_str(digital_str)
//   guard check is None else { raise check.unwrap() }
//   { polarity: Some(polarity), value: digital_str }
// }

///|
pub impl Show for UnlimitInt with output(self : UnlimitInt, logger : &Logger) -> Unit {
  // self.output(logger)
  logger.write_object(self)
}

///|
pub impl Show for UnlimitInt with to_string(self : UnlimitInt) -> String {
  self.value
}

///|
pub impl Eq for UnlimitInt with op_equal(self : UnlimitInt, other : UnlimitInt) -> Bool {
  guard self.sign == other.sign else { return false }
  guard self.value.length() == other.value.length() else { return false }
  for index = 0; index < self.value.length(); index = index + 1 {
    guard self.value.char_at(index) == other.value.char_at(index) else {
      return false
    }

  }
  return true
}

///|
pub fn UnlimitInt::is_zero(self : UnlimitInt) -> Bool {
  if self.sign is None && self.value == "0" {
    return true
  }
  return false
}

///|
fn UnlimitInt::real_add(value1 : String, value2 : String) -> String {
  let max_length = if value1.length() == value2.length() {
    value1.length()
  } else if value1.length() > value2.length() {
    value1.length()
  } else {
    value2.length()
  }
  let result = StringBuilder::new()
  for index = 0; index < max_length; index = index + 1 {
    let index1 = value1.length() - 1 - index
    let index2 = value2.length() - 1 - index
    if index1 >= value1.length() {
      //todo
    }
    if index2 >= value2.length() {
      //todo
    }
    //need check index overflow
    let v1_char = value1.char_at(index1)
    let v2_char = value2.char_at(index2)

  }
  ""
}

///|
fn UnlimitInt::real_sub(value1 : String, value2 : String) -> (Sign?, String) {
  //大正+小负=正 -- 符号不变 :::: self.value-other.value in real_sub
  //小正+大负=负 -- 符号不变 :::: other.value-self.value in real_sub
  //大负+小正=负 -- 符号不变 :::: self.value-other.value in real_sub
  //小负+大正=正 -- 符号变正 :::: other.value-self.value in real_sub
  //todo
  (None, "0")
}

///|
pub impl Add for UnlimitInt with op_add(self : UnlimitInt, other : UnlimitInt) -> UnlimitInt {
  //check zero
  match (self.is_zero(), other.is_zero()) {
    (true, true) => return UnlimitInt::default()
    (true, false) => return other
    (false, true) => return self
  }

  //check polarity
  let self_p = self.sign.unwrap()
  let other_p = self.sign.unwrap()

  // symbols equal
  if self_p == other_p {
    let result = UnlimitInt::real_add(self.value, other.value)
    let real_result = { sign: Some(self_p), value: result }
    return real_result
  }
  let both_equal = fn() -> UnlimitInt {
    let result = UnlimitInt::real_add(self.value, other.value)
    let real_result = { sign: Some(self_p), value: result }
    real_result
  }
  let both_not_equal = fn(a : String, b : String) -> UnlimitInt {
    let result = UnlimitInt::real_sub(a, b)
    if result.0 is None && result.1 == "0" {
      return UnlimitInt::make_zero()
    }
    let real_result = { sign: result.0, value: result.1 }
    return real_result
  }

  //symbols not equal
  match (self_p, other_p) {
    //++
    (Sign::Positive, Sign::Positive) => return both_equal()
    //--
    (Sign::Negative, Sign::Negative) => return both_equal()
    //+-
    (Sign::Positive, Sign::Negative) =>
      return both_not_equal(self.value, other.value)
    //-+
    (Sign::Negative, Sign::Positive) =>
      return both_not_equal(other.value, self.value)
  }
}

///|
pub impl Sub for UnlimitInt with op_sub(self : UnlimitInt, other : UnlimitInt) -> Bool {
  //todo
  true
}

///|
pub impl Mul for UnlimitInt with op_mul(self : UnlimitInt, other : UnlimitInt) -> Bool {
  //todo
  true
}

///|
pub impl Div for UnlimitInt with op_div(self : UnlimitInt, other : UnlimitInt) -> Bool {
  //todo
  true
}

///|
pub impl Mod for UnlimitInt with op_mod(self : UnlimitInt, other : UnlimitInt) -> Bool {
  //todo
  true
}

///|`0` for equal, `-1` for smaller, `1` for greater
pub impl Compare for UnlimitInt with compare(
  self : UnlimitInt,
  other : UnlimitInt
) -> Int {
  if self == other {
    return 0
  }

  //compare polarity
  let self_polarity = self.sign.unwrap()
  let other_polarity = other.sign.unwrap()
  if self_polarity == Sign::Negative && other_polarity == Sign::Positive {
    return -1
  }
  if self_polarity == Sign::Positive && other_polarity == Sign::Negative {
    return 1
  }
  //compare value length
  if self.value.length() < other.value.length() {
    return -1
  }
  if self.value.length() > other.value.length() {
    return 1
  }
  // compare value using compute ,both vlaue length  are equal
  // values polarity is +
  if self_polarity == other_polarity && self_polarity == Sign::Positive {
    //todo compute op sub
  }
  // values polarity is -
  if self_polarity == other_polarity && self_polarity == Sign::Negative {
    //todo compute op sub
  }
  return 0

  //todo
}
